package com.zmn.plat.business.impl.service.group;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import com.zmn.plat.model.entity.pilot.ChannelPriceQuery;
import com.zmn.plat.services.interfaces.pilot.ChannelPriceService;
import org.springframework.beans.BeanUtils;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.math.MathUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.plat.business.interfaces.service.group.ServiceGroupBService;
import com.zmn.plat.common.dictionary.PlatErrorCodeDict;
import com.zmn.plat.common.dto.service.group.ServiceGroupDIO;
import com.zmn.plat.common.dto.service.group.ServiceGroupDRO;
import com.zmn.plat.common.dto.service.item.ServiceItemDRO;
import com.zmn.plat.common.exception.PlatException;
import com.zmn.plat.manager.dictionary.MasterDict;
import com.zmn.plat.model.entity.servcategory.ServAssCategoryQuery;
import com.zmn.plat.model.entity.service.group.ServiceGroup;
import com.zmn.plat.model.entity.service.group.ServiceGroupQuery;
import com.zmn.plat.model.entity.service.item.ServiceItem;
import com.zmn.plat.model.entity.service.item.ServiceItemQuery;
import com.zmn.plat.model.entity.service.item.config.ServiceItemTimeConfig;
import com.zmn.plat.model.entity.warranty.info.WarrantyInfo;
import com.zmn.plat.model.entity.warranty.info.WarrantyInfoQuery;
import com.zmn.plat.model.vo.service.group.ServiceGroupCopyVO;
import com.zmn.plat.model.vo.service.group.ServiceGroupVO;
import com.zmn.plat.model.vo.service.item.ServiceItemVO;
import com.zmn.plat.services.interfaces.servcategory.ServAssCategoryService;
import com.zmn.plat.services.interfaces.service.group.ServiceGroupService;
import com.zmn.plat.services.interfaces.service.item.ServiceItemService;
import com.zmn.plat.services.interfaces.service.item.config.ServiceItemTimeConfigService;
import com.zmn.plat.services.interfaces.warranty.info.WarrantyInfoService;

import lombok.extern.slf4j.Slf4j;

/**
 * @author tanbiao
 * @description
 * @modifier
 * @since 2019/11/25 16:29
 **/
@Service
@Slf4j
public class ServiceGroupBServiceImpl implements ServiceGroupBService {
    private final static int NAME_LENGTH = 50;
    @Resource
    private ServiceGroupService faultGroupService;
    @Resource
    private ServiceItemService faultItemService;
    @Resource
    private ServAssCategoryService servAssCategoryService;
    @Resource
    protected ChannelPriceService channelPriceService;
    @Resource
    protected WarrantyInfoService warrantyInfoService;
    @Resource
    protected ServiceItemTimeConfigService faultItemTimeConfigService;

    @Override
    public ServiceGroup findByKey(ServiceGroupQuery query) {
        ServiceGroup faultGroup = null;
        if (query.getGroupId() == null || query.getGroupId() == 0) {
            faultGroup = new ServiceGroup();
            faultGroup.setServCategId(query.getServCategId());
            faultGroup.setCategOneId(query.getCategOneId());
            faultGroup.setTariffId(query.getTariffId());
        } else {
            faultGroup = faultGroupService.findByKey(query.getGroupId());
        }
        return faultGroup;
    }

    @Override
    public ServiceGroupDRO getById(Integer groupId) {
        if (NumberUtil.isNullOrZero(groupId)) {
            log.error("groupid is null..");
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }

        ServiceGroup faultGroup = faultGroupService.findByKey(groupId);
        ServiceGroupDRO dro = new ServiceGroupDRO();
        BeanCopier copier = BeanCopier.create(ServiceGroup.class, ServiceGroupDRO.class, false);
        copier.copy(faultGroup, dro, null);
        return dro;
    }

    @Override
    public Boolean checkFixPriceByChannelIdAndCityIdAndProvinceId(Integer channelId, Integer cityId, Integer provinceId) {
        if (NumberUtil.isNullOrZero(channelId) || NumberUtil.isNullOrZero(cityId) || NumberUtil.isNullOrZero(provinceId)) {
            log.error("param is not valiable.channelId={},cityId={},provinceId={}", channelId, cityId, provinceId);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }

        ChannelPriceQuery channelPriceQuery = new ChannelPriceQuery();
        channelPriceQuery.setProvinceId(provinceId);
        channelPriceQuery.setChannelId(channelId);
        channelPriceQuery.setCityId(cityId);
        Integer count = channelPriceService.countByQuery(channelPriceQuery);
        return count > 0;
    }

    @Override
    public List<ServiceGroupDRO> listByDIO(ServiceGroupDIO query) {
        if (Objects.isNull(query)) {
            log.error("query is null..");
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }

        ServiceGroupQuery groupQuery = new ServiceGroupQuery();
        BeanCopier copier = BeanCopier.create(ServiceGroupDIO.class, ServiceGroupQuery.class, false);
        copier.copy(query, groupQuery, null);
        List<ServiceGroup> serviceGroups = faultGroupService.listByQuery(groupQuery);
        BeanCopier copierDRO = BeanCopier.create(ServiceGroup.class, ServiceGroupDRO.class, false);
        List<ServiceGroupDRO> serviceGroupDROS = new ArrayList<>();
        ServiceGroupDRO faultGroupDRO = null;
        for (int i = 0; i < serviceGroups.size(); i++) {
            faultGroupDRO = new ServiceGroupDRO();
            copierDRO.copy(serviceGroups.get(i), faultGroupDRO, null);
            serviceGroupDROS.add(faultGroupDRO);
        }
        return serviceGroupDROS;
    }

    @Override
    public List<ServiceItemDRO> listByProductId(Integer productId) {
        if (!NumberUtil.isPositiveInteger(productId)) {
            log.error("productId is null..");
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }

        List<ServiceItem> faultItems = faultItemService.listByProductId(productId);
        BeanCopier copierDRO = BeanCopier.create(ServiceItem.class, ServiceItemDRO.class, false);
        List<ServiceItemDRO> list = new ArrayList<>();
        ServiceItemDRO faultItemDRO = null;
        for (int i = 0; i < faultItems.size(); i++) {
            faultItemDRO = new ServiceItemDRO();
            copierDRO.copy(faultItems.get(i), faultItemDRO, null);
            list.add(faultItemDRO);
        }
        return list;
    }

    @Override
    public List<ServiceGroupVO> listGroupVOByQuery(ServiceGroupQuery query) {
        List<ServiceGroup> groups = faultGroupService.listByQuery(query);
        if (!CollectionUtils.isEmpty(groups)) {
            List<ServiceGroupVO> groupVOS = new ArrayList<>(groups.size());
            ServiceItemQuery itemQuery = new ServiceItemQuery();
            for (ServiceGroup group : groups) {
                ServiceGroupVO groupVO = new ServiceGroupVO();
                BeanUtils.copyProperties(group, groupVO);
                itemQuery.setGroupId(group.getGroupId());
                itemQuery.setTariffId(group.getTariffId());
                List<ServiceItem> list = faultItemService.listByQuery(itemQuery);
                List<ServiceItemVO> listVo = new ArrayList<>();
                // 所有服务项都被禁用，出现删除分组按钮
                list.forEach(e -> {
                    ServiceItemVO faultItemVO = new ServiceItemVO();
                    BeanUtils.copyProperties(e, faultItemVO);
                    faultItemVO.setHourFeeYuan(narrow(faultItemVO.getHourFee()));
                    faultItemVO.setTrafficFeeYuan(narrow(faultItemVO.getTrafficFee()));
                    listVo.add(faultItemVO);
                });
                // 所有服务项都被禁用，出现删除分组按钮
                List<ServiceItemVO> enabledItems = listVo.stream().filter(e -> e.getStatus().equals(GlobalConsts.YES)).collect(Collectors.toList());
                groupVO.setGroupCanDelete(GlobalConsts.NO);
                if (CollectionUtils.isEmpty(enabledItems)) {
                    groupVO.setGroupCanDelete(GlobalConsts.YES);
                }
                groupVO.setItems(listVo);
                groupVOS.add(groupVO);
            }
            return groupVOS;
        }
        return null;
    }

    @Override
    public Integer addEdit(ServiceGroup faultGroup, String operator) {
        Date now = DateUtil.getNow();
        Integer groupId = faultGroup.getGroupId();
        Integer result = -1;
        if (groupId == null || groupId == 0) {
            faultGroup.setCreater(operator);
            faultGroup.setCreateTime(now);
            result = faultGroupService.insert(faultGroup);
        } else {
            faultGroup.setUpdater(operator);
            faultGroup.setUpdateTime(now);
            result = faultGroupService.updateByKey(faultGroup);
        }
        // 更新操作时间
        ServAssCategoryQuery servAssCategoryQuery = new ServAssCategoryQuery();
        servAssCategoryQuery.setFaultUpdater(operator);
        servAssCategoryQuery.setFaultUpdateTime(now);
        servAssCategoryQuery.setServCategId(faultGroup.getServCategId());
        servAssCategoryQuery.setCategOneId(faultGroup.getCategOneId());

        servAssCategoryService.updateFaultUpdaterAndTimeByServCategIdAndCategOneId(servAssCategoryQuery);
        return result;
    }

    @Override
    public Integer copyGroupData(ServiceGroupCopyVO faultGroup, String mcStaffRealName) {
        // String nameTail = "(复制"+DateUtil.getNowFormatted("SSS")+")";
        List<ServiceGroup> groupList = faultGroupService.listByGroupIds(faultGroup.getGroupIds());
        List<ServiceItem> itemList = new ArrayList<>();
        Integer tariffId = faultGroup.getTariffId();
        ServiceItemQuery itemQuery = new ServiceItemQuery();
        Date currentDate = new Date();
        Integer result = -1;
        // 被复制的所有项目id
        List<Integer> itemIds = new ArrayList<>();
        for (ServiceGroup group : groupList) {
            itemQuery.setGroupId(group.getGroupId());
            List<ServiceItem> groupItems = faultItemService.listByQuery(itemQuery);
            // 1.修改服务分组价格表id
            group.setTariffId(tariffId);
            // 2.分组修改别名,为避免重复，将别名添加毫秒的时间戳
            setGroupCommonMsg(group, currentDate, mcStaffRealName);
            result = faultGroupService.insert(group);
            Integer groupId = group.getGroupId();
            if (!CollectionUtils.isEmpty(groupItems)) {
                groupItems.forEach(e -> {
                    setItemCommonMsg(e, groupId, tariffId, currentDate, mcStaffRealName);
                });
                itemList.addAll(groupItems);
            }
        }

        itemIds = itemList.stream().map(e -> e.getItemId()).collect(Collectors.toList());

        // 3.复制分组下的项目
        Map<Integer, ServiceItem> itemNewOldRelationMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(itemList)) {
            BeanCopier itemCopier = BeanCopier.create(ServiceItem.class, ServiceItemVO.class, false);
            List<ServiceItemVO> itemVoList = itemList.stream().map(e -> {
                ServiceItemVO vo = new ServiceItemVO();
                itemCopier.copy(e, vo, null);
                vo.setOldItemId(e.getItemId());
                return vo;
            }).collect(Collectors.toList());
            result = faultItemService.insertBatch(itemVoList);
            // 整理出新旧关系
            itemVoList.forEach(e -> itemNewOldRelationMap.put(e.getOldItemId(), e));
        }

        // 处理保修信息
        List<WarrantyInfo> warrantyInfos = new ArrayList<>();
        // 复制时间配置信息
        List<ServiceItemTimeConfig> timeConfigs = new ArrayList<>();
        if (!CollectionUtils.isEmpty(itemIds)) {
            WarrantyInfoQuery warrantyInfoQuery = new WarrantyInfoQuery();
            warrantyInfoQuery.setItemIds(itemIds);
            warrantyInfos = warrantyInfoService.listByQuery(warrantyInfoQuery);
            timeConfigs = faultItemTimeConfigService.listByItemIdList(itemIds);
        }
        if (!CollectionUtils.isEmpty(warrantyInfos)) {
            warrantyInfos.forEach(e -> {
                setWarrantyInfoCommonMsg(e, tariffId, mcStaffRealName, itemNewOldRelationMap.get(e.getItemId()));
            });
            warrantyInfoService.insertBatch(warrantyInfos);
        }
        if (!CollectionUtils.isEmpty(timeConfigs)) {
            timeConfigs.forEach(e -> {
                setTimeConfigCommonMsg(e, itemNewOldRelationMap.get(e.getItemId()));
            });
            faultItemTimeConfigService.insertBatch(timeConfigs);
        }
        return result;
    }

    private void setItemCommonMsg(ServiceItem e, Integer groupId, Integer tariffId, Date currentDate, String operator) {
        e.setGroupId(groupId);
        e.setTariffId(tariffId);
        e.setCreateTime(currentDate);
        e.setCreateTime(currentDate);
        e.setUpdater(operator);
        e.setCreater(operator);
    }

    private void setWarrantyInfoCommonMsg(WarrantyInfo e, Integer tariffId, String operator, ServiceItem faultItem) {
        e.setTariffId(tariffId);
        e.setCreateTime(new Date());
        e.setUpdateTime(new Date());
        e.setUpdater(operator);
        e.setCreater(operator);
        e.setItemId(faultItem.getItemId());
    }

    private void setTimeConfigCommonMsg(ServiceItemTimeConfig e, ServiceItem faultItem) {
        e.setTariffId(faultItem.getTariffId());
        e.setCreateTime(faultItem.getCreateTime());
        e.setUpdateTime(faultItem.getUpdateTime());
        e.setUpdater(faultItem.getUpdater());
        e.setCreater(faultItem.getCreater());
        e.setItemId(faultItem.getItemId());
        e.setGroupId(faultItem.getGroupId());
    }

    private void setGroupCommonMsg(ServiceGroup group, Date currentDate, String operator) {
        String newAliasName = "(复制)" + group.getGroupAlias();
        if (newAliasName.length() > NAME_LENGTH) {
            newAliasName = newAliasName.substring(0, NAME_LENGTH - 1);
        }
        group.setGroupAlias(newAliasName);
        String groupName = "(复制)" + group.getGroupName();
        if (groupName.length() > NAME_LENGTH) {
            groupName = groupName.substring(0, NAME_LENGTH - 1);
        }
        group.setGroupName(groupName);
        group.setCreateTime(currentDate);
        group.setCreateTime(currentDate);
        group.setUpdater(operator);
        group.setCreater(operator);
    }

    private String narrow(Object dividend) {
        if (Objects.isNull(dividend)) {
            return "";
        }
        double div = MathUtil.div(Integer.parseInt(dividend.toString()), MasterDict.COEFFICIENT_MAGNIFICATION);
        BigDecimal b = new BigDecimal(div);
        return b.setScale(2, BigDecimal.ROUND_HALF_UP).toString();
    }
}
